export default class Queue {

  constructor(workerLen) {
    this.workerLen = workerLen ?? 3; // The default control parallelism is 3
    this.list = [];
    this.worker = new Array(this.workerLen);
    this.onTaskCompletedCallback = null;
  }

  // Execute a task
  async executionFunc(index, tagFunction) {
    let result = null;
    const { tag, fn } = tagFunction;
    const res = await fn().catch(() => {
      result = '';
      if (this.onTaskCompletedCallback) {
        this.onTaskCompletedCallback(-1, tag, result);
      }
    });
    result = res;
    this.worker[index] = undefined;
    if (this.onTaskCompletedCallback) {
      this.onTaskCompletedCallback(1, tag, result);
    }
    this.run();
  }

  // Add to task queue
  addList(list) {
    for (let i = 0; i < list.length; i++) {
      this.list.unshift(list[i]);
    }
  }

  // Assign and execute tasks
  async run() {
    const runIndex = [];
    for (let i = 0; i < this.workerLen; i++) {
      const len = this.list.length;

      if (!this.worker[i] && len > 0) {
        this.worker[i] = this.executionFunc(i, this.list[len - 1]);
        runIndex.push(i);
        this.list.pop();
      }
    }
    for (let i = 0; i < runIndex.length; i++) {
      await this.worker[runIndex[i]];
    }
  }

  setOnTaskCompletedCallback(callback) {
    this.onTaskCompletedCallback = callback;
  }
}